﻿////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// <copyright>Copyright 2008-2011 Andreas Huber Doenni</copyright>
// Distributed under the GNU General Public License version 2 (GPLv2).
// See accompanying file License.txt or copy at http://phuse.codeplex.com/license.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

namespace Phuse.Mime
{
    using System;
    using System.Collections.Generic;

    /// <summary>Processes header fields containing an address list, e.g. From.</summary>
    internal sealed class AddressListHeaderFieldBodyProcessor : HeaderFieldBodyProcessor
    {
        private bool mayBeEmptyGroup;
        private bool inEmailAddress;
        private EncodedWordDecoder current = new EncodedWordDecoder(75, 4);
        private string currentDisplayName;
        private readonly AddressListHeaderField result;

        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        internal AddressListHeaderFieldBodyProcessor(string fieldName)
        {
            this.result = new AddressListHeaderField(fieldName);
        }

        internal sealed override void ProcessNormalBodyEvent(byte ev)
        {
            switch (ev)
            {
                case (byte)':':
                    if (string.IsNullOrEmpty(this.currentDisplayName))
                    {
                        this.SetDisplayName(true);
                    }

                    break;
                case (byte)'<':
                    if (!this.inEmailAddress)
                    {
                        this.inEmailAddress = true;
                        this.SetDisplayName(false);
                    }

                    break;
                case (byte)'>':
                    if (this.inEmailAddress)
                    {
                        this.inEmailAddress = false;
                        this.AddAddressIfValid(false);
                    }

                    break;
                case (byte)';':
                    this.AddAddressIfValid(true);
                    break;
                case (byte)',':
                    this.AddAddressIfValid(false);
                    break;
                default:
                    this.current.ProcessEvent(ev, this.inEmailAddress);
                    break;
            }
        }

        internal sealed override void ProcessQuotedBodyEvent(byte ev, bool isQuoteChar)
        {
            if (!isQuoteChar)
            {
                this.current.ProcessEvent(ev, true);
            }
        }

        internal sealed override void ProcessCommentBodyEvent(byte ev)
        {
            // Intentional: Ignore all comments
        }

        internal sealed override HeaderField GetHeaderField()
        {
            this.AddAddressIfValid(false);
            return this.result;
        }

        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        private void SetDisplayName(bool isGroupName)
        {
            this.mayBeEmptyGroup = isGroupName;
            this.currentDisplayName = this.GetCurrentString();
        }

        private void AddAddressIfValid(bool isGroupEnd)
        {
            var emailAddress = this.GetCurrentString();

            if (this.mayBeEmptyGroup && isGroupEnd &&
                !string.IsNullOrEmpty(this.currentDisplayName) && string.IsNullOrEmpty(emailAddress))
            {
                this.result.Addresses.Add(new Address(this.currentDisplayName));
            }
            else
            {
                if (!string.IsNullOrEmpty(this.currentDisplayName) || !string.IsNullOrEmpty(emailAddress))
                {
                    this.result.Addresses.Add(new Address(this.currentDisplayName, emailAddress));
                }
            }

            this.mayBeEmptyGroup = false;
            this.inEmailAddress = false;
            this.currentDisplayName = null;
        }

        private string GetCurrentString()
        {
            string currentString = this.current.GetResult();
            this.current = new EncodedWordDecoder(75, 4);
            return currentString;
        }
    }
}
